// Copyright 2015 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifndef IPC_IPC_MESSAGE_TEMPLATES_IMPL_H_
#define IPC_IPC_MESSAGE_TEMPLATES_IMPL_H_

namespace IPC {

template <typename... Ts>
class ParamDeserializer : public MessageReplyDeserializer {
public:
    explicit ParamDeserializer(const base::Tuple<Ts&...>& out)
        : out_(out)
    {
    }

    bool SerializeOutputParameters(const IPC::Message& msg,
        base::PickleIterator iter) override
    {
        return ReadParam(&msg, &iter, &out_);
    }

    base::Tuple<Ts&...> out_;
};

template <typename Meta, typename... Ins>
MessageT<Meta, base::Tuple<Ins...>, void>::MessageT(Routing routing,
    const Ins&... ins)
    : Message(routing.id, ID, PRIORITY_NORMAL)
{
    WriteParam(this, base::MakeRefTuple(ins...));
}

template <typename Meta, typename... Ins>
bool MessageT<Meta, base::Tuple<Ins...>, void>::Read(const Message* msg,
    Param* p)
{
    base::PickleIterator iter(*msg);
    return ReadParam(msg, &iter, p);
}

template <typename Meta, typename... Ins>
void MessageT<Meta, base::Tuple<Ins...>, void>::Log(std::string* name,
    const Message* msg,
    std::string* l)
{
    if (name)
        *name = Meta::kName;
    if (!msg || !l)
        return;
    Param p;
    if (Read(msg, &p))
        LogParam(p, l);
}

template <typename Meta, typename... Ins, typename... Outs>
MessageT<Meta, base::Tuple<Ins...>, base::Tuple<Outs...>>::MessageT(
    Routing routing,
    const Ins&... ins,
    Outs*... outs)
    : SyncMessage(
        routing.id,
        ID,
        PRIORITY_NORMAL,
        new ParamDeserializer<Outs...>(base::MakeRefTuple(*outs...)))
{
    WriteParam(this, base::MakeRefTuple(ins...));
}

template <typename Meta, typename... Ins, typename... Outs>
bool MessageT<Meta, base::Tuple<Ins...>, base::Tuple<Outs...>>::ReadSendParam(
    const Message* msg,
    SendParam* p)
{
    base::PickleIterator iter = SyncMessage::GetDataIterator(msg);
    return ReadParam(msg, &iter, p);
}

template <typename Meta, typename... Ins, typename... Outs>
bool MessageT<Meta, base::Tuple<Ins...>, base::Tuple<Outs...>>::ReadReplyParam(
    const Message* msg,
    ReplyParam* p)
{
    base::PickleIterator iter = SyncMessage::GetDataIterator(msg);
    return ReadParam(msg, &iter, p);
}

template <typename Meta, typename... Ins, typename... Outs>
void MessageT<Meta,
    base::Tuple<Ins...>,
    base::Tuple<Outs...>>::WriteReplyParams(Message* reply,
    const Outs&... outs)
{
    WriteParam(reply, base::MakeRefTuple(outs...));
}

template <typename Meta, typename... Ins, typename... Outs>
void MessageT<Meta, base::Tuple<Ins...>, base::Tuple<Outs...>>::Log(
    std::string* name,
    const Message* msg,
    std::string* l)
{
    if (name)
        *name = Meta::kName;
    if (!msg || !l)
        return;
    if (msg->is_sync()) {
        SendParam p;
        if (ReadSendParam(msg, &p))
            LogParam(p, l);
        AddOutputParamsToLog(msg, l);
    } else {
        ReplyParam p;
        if (ReadReplyParam(msg, &p))
            LogParam(p, l);
    }
}

} // namespace IPC

#endif // IPC_IPC_MESSAGE_TEMPLATES_IMPL_H_
